package book

import (
	"NovelBook/dao"
	"NovelBook/models/db_models"
	"context"
	"errors"
	"time"

	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"
)

func BorrowBooksByUniqueID(borrowerID uint, bookUniqueIDs []string) error {
	var books []db_models.BooksNumber
	// 查找书籍
	err := dao.GetDb().Preload("Book").Where("book_unique_id IN (?)", bookUniqueIDs).Find(&books).Error
	if err != nil {
		return err
	}

	// 有不存在书籍返回error
	if len(books) != len(bookUniqueIDs) {
		return errors.New("books don't exist")
	}

	// 检查并生成借阅记录
	var borrowTables []db_models.BorrowTable
	if borrowTables, err = BorrowCheck(borrowerID, books); err != nil {
		return err
	}

	// 调用事务
	err = BorrowTransaction(borrowerID, books, borrowTables)
	if err != nil {
		return err
	}

	switch err := IncBRNumbers(1); err != nil {
	case true:
		return err
	}

	return nil
}

// BorrowCheck 借书检查，生成借阅记录
func BorrowCheck(borrowerID uint, books []db_models.BooksNumber) ([]db_models.BorrowTable, error) {
	// 检查书籍库存
	for _, book := range books {
		if book.State != 0 {
			return nil, errors.New("the book has been borrowed")
		}
	}

	// 检查用户借阅数量
	var borrower db_models.Borrower
	if err := dao.GetDb().Where("id = ?", borrowerID).Find(&borrower).Error; err != nil {
		return nil, err
	}

	if borrower.Borrowed+uint8(len(books)) > db_models.MaxBorrow {
		return nil, errors.New("exceeding the maximum quantity")
	}

	// 检查用户所有借阅书籍是否有超时的
	var borrowed []db_models.BorrowTable
	if err := dao.GetDb().Where("borrower_id = ? AND is_returned = ?", borrowerID, 0).Find(&borrowed).Error; err != nil {
		return nil, err
	}

	for _, borrowTable := range borrowed {
		if !borrowTable.IsReturned && time.Now().UnixNano()/int64(time.Millisecond)-borrowTable.StartTime > db_models.MaxTime {
			return nil, errors.New("there are overdue books")
		}
	}

	// 借阅记录
	nowTs := time.Now().UnixNano() / int64(time.Millisecond)
	var borrowTables []db_models.BorrowTable
	for _, book := range books {
		borrowTables = append(borrowTables, db_models.BorrowTable{
			BorrowerID:    borrowerID,
			BookID:        book.BookID,
			BooksNumberID: book.BookNo,
			StartTime:     nowTs,
			IsReturned:    false,
		})
	}

	return borrowTables, nil
}

// BorrowTransaction 借书事务
func BorrowTransaction(borrowerID uint, books []db_models.BooksNumber, borrowTables []db_models.BorrowTable) error {

	// 开启事务
	tx := dao.GetDb().Begin()
	if err := tx.Error; err != nil {
		return err
	}

	// 更新用户借阅记录数
	if err := tx.Model(&db_models.Borrower{}).Where("id = ?", borrowerID).
		UpdateColumn("borrowed", gorm.Expr("borrowed + ?", len(borrowTables))).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 更新书籍索引表的State字段为borrowerID
	for _, book := range books {
		if err := tx.Model(&db_models.BooksNumber{}).Where("book_unique_id = ?", book.BookUniqueID).
			UpdateColumn("state", borrowerID).Error; err != nil {
			tx.Rollback()
			return err
		}

		// 更新书籍库存
		if err := tx.Model(&db_models.Books{}).Where("id = (?)", book.BookID).
			UpdateColumn("stock", gorm.Expr("stock - ?", 1)).Error; err != nil {
			tx.Rollback()
			return err
		}

	}

	// 添加借阅记录
	if err := tx.Create(&borrowTables).Error; err != nil {
		tx.Rollback()
		return err
	}

	return tx.Commit().Error
}

func IncBRNumbers(number int64) error {
	// 增加redis中的借还书人数
	ctx := context.Background()
	today := time.Now().Format("2006-01-02")
	// TTL设置为今天的剩余时间
	remainingTime := time.Until(time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 23, 59, 59, 0, time.Now().Location()))

	if _, err := dao.Get("br_numbers:" + today); err != nil {
		if err == redis.Nil {
			if err := dao.Set("br_numbers:"+today, 0, remainingTime); err != nil {
				return err
			}
		} else {
			return err
		}
	}
	if err := dao.Rdb.IncrBy(ctx, "br_numbers:"+today, number).Err(); err != nil {
		return err
	}
	return nil
}
